﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NHibernate;
using NHibernate.Cfg;
using NHibernate.Tool.hbm2ddl;

namespace Domain
{
    public sealed class Conexion
    {
        private static readonly Conexion instance = new Conexion();
        private static ISessionFactory mSessionFactory;
        private static Configuration mNHConfig;
        private static ISession mSession;
        private static ITransaction mTransaction;

        /// <summary>
        /// Definiciones necesarias para implementar el Patrón Singleton. 
        /// </summary>
        static Conexion(){}
        Conexion(){}

        public static Conexion Instance
        {
            get
            {
                return instance;
            }
        }
        

#region Manejo de Sesiones.
        
        public static ISession GetSession
        {
            get
            {
                if (mSession == null)
                    GetCurrentSession();
                else if (!mSession.IsOpen)
                    GetCurrentSession();
                return mSession;
            }
        }

        private static void GetCurrentSession()
        {
            mSession = GetSessionFactory().OpenSession();
        }

        private static ISessionFactory GetSessionFactory()
        {
            if (mSessionFactory == null)
                Init();
            return mSessionFactory;
        }

        private static void Init()
        {
            mNHConfig = new Configuration();
            mNHConfig.Configure();
            //_nhConfig.AddAssembly("MovieManager");
            //(new SchemaExport(configuration)).Create(true, true);
            mSessionFactory = mNHConfig.BuildSessionFactory();

        }
#endregion

#region Manejo de Transacciones.
        public static ITransaction IniciarTransaccion()
        {
            //TODO
            //En realidad no hay que devolver el objeto transaccion... 
            //Lo hice solo a modo ilustrativo...
            //Yo devolvería true o false si salió todo bien o no.
            //En caso de ya estar iniciada la transaccion... se puede lanzar alguna excepcion... 
            //o simplemente desde acá ignorarlo y que todo siga viento en popa... 
            try
            {
                if (mTransaction == null)
                    mTransaction = GetSession.BeginTransaction();
            }
            catch (Exception e)
            {
                //TODO
                //Dejar en un archivo de log del servidor el error que se produjo. 
                //Lanzar excepción o devolver mensaje de error. 
                //Ver si no es preferible devolver true o flase y recibir la entity por parametro referencial.
                throw e;
            }
            return mTransaction;
        }

        public static bool FinalizarTransaccion()
        {
            bool exito = true;
            try
            {
                if (mTransaction != null)
                    mTransaction.Commit();
            }
            catch (Exception e)
            {
                exito = false;
                //TODO
                //Dejar en un archivo de log del servidor el error que se produjo. 
                //Lanzar excepción o devolver mensaje de error. 
                //Ver si no es preferible devolver true o flase y recibir la entity por parametro referencial.
                throw e;
            }
            finally 
            {
                mTransaction = null;
            }
            return exito;
        }

        public static bool AbortarTransaccion()
        {
            bool exito = true;
            try
            {
                if (mTransaction != null)
                    mTransaction.Rollback();
            }
            catch (Exception e)
            {
                exito = false;
                //TODO
                //Dejar en un archivo de log del servidor el error que se produjo. 
                //Lanzar excepción o devolver mensaje de error. 
                //Ver si no es preferible devolver true o flase y recibir la entity por parametro referencial.
                throw e;
            }
            finally
            {
                mTransaction = null;
            }
            return exito;
        }

#endregion

    }
}